package com.ywu.bpmn.standard.service;

import com.ywu.boot.context.YwuContext;
import com.ywu.boot.context.YwuContextHolder;
import com.ywu.bpmn.spi.dto.YwuBpmnDto;
import com.ywu.bpmn.spi.vo.YwuBpmnVariableVo;
import com.ywu.common.result.CommonResult;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * @ClassName YwuActivitiService
 * @Description TODO
 * @Author GroundDemo
 * @Date 2025/4/23 10:49
 * @Version 1.0
 **/
@Service
@Slf4j
public class YwuActivitiService {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private TaskService taskService;

    /**
     * @Author GroundDemo
     * @Description 部署流程
     * @Date 11:15 2025/4/23
     * @Param [dto]
     * @return com.ywu.common.result.CommonResult<java.lang.Object>
     **/
    public CommonResult<Object> deployFlow(YwuBpmnDto dto) {
        Deployment deploy = repositoryService.createDeployment().key(dto.getKey())
                .name(dto.getName())
                .addString(dto.getKey() + ".bpmn", dto.getBpmn())
                .deploy();
        return CommonResult.success(deploy);
    }

    /**
    * @Author GroundDemo
    * @Description dto
    * @Date 11:10 2025/4/23
    * @Param [dto]
    * @return void
    **/
    @Async
    public void start(YwuBpmnDto dto, YwuContext currentContext) {
        YwuContextHolder.setCurrentContext(currentContext);
        if (CollectionUtils.isEmpty(dto.getVariable())) {
            runtimeService.startProcessInstanceByKey(dto.getKey());
        } else {
            runtimeService.startProcessInstanceByKey(dto.getKey(), dto.getVariable());
        }
    }

    /**
    * @Author GroundDemo
    * @Description 查询用户代办列表
    * @Date 11:16 2025/4/23
    * @Param [dto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> toDoList(YwuBpmnDto dto) {
        List<Task> test111 = taskService.createTaskQuery().taskAssignee(dto.getAssigneeName()).list();
        return CommonResult.success(test111.toString());
    }

    /**
    * @Author GroundDemo
    * @Description 用户审批
    * @Date 11:19 2025/4/23
    * @Param [dto]
    * @return void
    **/
    @Async
    public void complete(YwuBpmnDto dto, YwuContext currentContext) {
        YwuContextHolder.setCurrentContext(currentContext);
        if (Objects.isNull(dto.getVariable())) {
            taskService.complete(dto.getTaskId());
        } else {
            taskService.setVariables(dto.getTaskId(), dto.getVariable());
            taskService.complete(dto.getTaskId());
        }
    }

    /**
    * @Author GroundDemo
    * @Description 查询所有变量
    * @Date 11:19 2025/4/23
    * @Param [dto]
    * @return void
    **/
    public CommonResult<Object> queryAllVariables(YwuBpmnDto dto) {
        // 先判断流程实例状态
        Boolean isEnded = isProcessInstanceEnded(dto.getProcessInstanceId());
        if (isEnded == null) {
            // 流程实例不存在
            return CommonResult.error().setErrorCode("flow.instance.not.exist");
        }
        List<YwuBpmnVariableVo> ywuBpmnVariableVos = new ArrayList<>();
        if (!isEnded) {
            // 运行中：查询运行时变量（全局+局部）
            Map<String, Object> runtimeVariables = getRuntimeVariables(dto.getProcessInstanceId());
            for (String key : runtimeVariables.keySet()) {
                YwuBpmnVariableVo ywuBpmnVariableVo = new YwuBpmnVariableVo();
                ywuBpmnVariableVo.setName(key);
                ywuBpmnVariableVo.setValue(runtimeVariables.get(key));
                ywuBpmnVariableVos.add(ywuBpmnVariableVo);
            }
        } else {
            // 已结束：查询历史变量
            Map<String, Object> historicVariables = getHistoricVariables(dto.getProcessInstanceId());
            for (String key : historicVariables.keySet()) {
                YwuBpmnVariableVo ywuBpmnVariableVo = new YwuBpmnVariableVo();
                ywuBpmnVariableVo.setName(key);
                ywuBpmnVariableVo.setValue(historicVariables.get(key));
                ywuBpmnVariableVos.add(ywuBpmnVariableVo);
            }
        }
        return CommonResult.success(ywuBpmnVariableVos);
    }

    /**
    * @Author GroundDemo
    * @Description 检查流程实例是否已结束
    * @Date 11:19 2025/4/23
    * @Param [processInstanceId]
    * @return java.lang.Boolean
    **/
    public Boolean isProcessInstanceEnded(String processInstanceId) {
        // 检查运行时是否存在该流程实例（存在则未结束）
        ProcessInstance runtimeInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
        if (runtimeInstance != null) {
            // 运行中
            return false;
        }
        // 运行时不存在，检查历史记录（存在则已结束）
        HistoricProcessInstance historicInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        if (historicInstance != null) {
            // 已结束
            return true;
        }
        // 两者都不存在，说明流程实例ID无效
        return null;
    }

    /**
    * @Author GroundDemo
    * @Description 获取流程实例的所有变量
    * @Date 11:19 2025/4/23
    * @Param [processInstanceId]
    * @return java.util.Map<java.lang.String,java.lang.Object>
    **/
    private Map<String, Object> getRuntimeVariables(String processInstanceId) {
        // 1. 全局变量
        return runtimeService.getVariables(processInstanceId);
    }


    /**
    * @Author GroundDemo
    * @Description 获取已结束流程实例的所有历史变量
    * @Date 11:19 2025/4/23
    * @Param [processInstanceId]
    * @return java.util.Map<java.lang.String,java.lang.Object>
    **/
    private Map<String, Object> getHistoricVariables(String processInstanceId) {
        Map<String, Object> historicVariables = new HashMap<>();
        List<HistoricVariableInstance> variableInstances = historyService.createHistoricVariableInstanceQuery()
                .processInstanceId(processInstanceId).list();
        for (HistoricVariableInstance variable : variableInstances) {
            historicVariables.put(variable.getVariableName(), variable.getValue());
        }
        return historicVariables;
    }
}
